package com.time.client.domain.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.time.client.common.entity.PageResult;
import com.time.client.common.enums.AuditStatusEnum;
import com.time.client.common.enums.IsActiveStatusEnum;
import com.time.client.common.enums.IsDeletedFlagEnum;
import com.time.client.domain.constants.ExceptionCode;
import com.time.client.domain.converter.FriendLinkBOConverter;
import com.time.client.domain.entity.FriendLinkBO;
import com.time.client.domain.exception.AlreadyExistsException;
import com.time.client.domain.redis.RedisUtil;
import com.time.client.domain.service.ClientFriendLinkDomainService;
import com.time.client.infra.basic.entity.FriendLink;
import com.time.client.infra.basic.service.FriendLinkService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 友链管理领域服务层实现类
 *
 * @author: HuangQi
 * @date: Created in 16:15 2025/10/31
 * @description: 友链管理领域服务层实现类
 */
@Slf4j
@Service("clientFriendLinkDomainService")
public class ClientFriendLinkDomainServiceImpl implements ClientFriendLinkDomainService {

    @Autowired
    private FriendLinkService friendLinkService;
    @Autowired
    private RedisUtil redisUtil;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final long FRIEND_LINK_CACHE_TIMEOUT_MINUTES = 30L;
    private static final long FRIEND_LINK_CACHE_JITTER_MINUTES = 10L;
    private static final TimeUnit FRIEND_LINK_CACHE_TIMEUNIT = TimeUnit.MINUTES;

    @Override
    public Boolean add(FriendLinkBO friendLinkBO) {
        if (log.isInfoEnabled()) {
            log.info("ClientFriendLinkDomainServiceImpl.add.bo:{}", friendLinkBO);
        }

        // 参数转换
        FriendLink friendLink = FriendLinkBOConverter.INSTANCE.convertBOToEntity(friendLinkBO);
        friendLink.setStatus(IsActiveStatusEnum.UN_ACTIVE.getCode());
        friendLink.setAuditStatus(AuditStatusEnum.PENDING_AUDIT.getCode());
        friendLink.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 检查当前友链的名称是否已经存在
        if (isExistFriendLink(friendLink.getLinkName())) {
            throw new AlreadyExistsException(ExceptionCode.FRIENDLINK_ALREADY_EXISTS, "该友链名称已经存在");
        }

        // 调用 service
        int count = friendLinkService.insert(friendLink);

        return count > 0;
    }

    /**
     * 检查友链名称是否已经存在
     *
     * @param linkName 友链名称
     * @return 是否存在，true-存在，false-不存在
     */
    private boolean isExistFriendLink(String linkName) {
        FriendLink friendLink = friendLinkService.queryByLinkName(linkName);
        return !Objects.isNull(friendLink);
    }


    @Override
    public PageResult<FriendLinkBO> queryAllFriendLink(FriendLinkBO friendLinkBO) {
        if (log.isInfoEnabled()) {
            log.info("ClientFriendLinkDomainServiceImpl.queryAllFriendLink.bo:{}", friendLinkBO);
        }

        String cacheKey = redisUtil.buildKey("client", "friendLink", "queryAll", serializeKey(friendLinkBO));
        PageResult<FriendLinkBO> cacheResult = getCache(cacheKey, new TypeReference<PageResult<FriendLinkBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 参数转换
        FriendLink friendLink = FriendLinkBOConverter.INSTANCE.convertBOToEntity(friendLinkBO);
        friendLink.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 创建分页结果
        PageResult<FriendLinkBO> pageResult = new PageResult<>();
        pageResult.setPageNo(friendLinkBO.getPageNo());
        pageResult.setPageSize(friendLinkBO.getPageSize());

        // 获取总记录数
        int total = friendLinkService.countAll();
        pageResult.setTotal(total);

        // 获取分页的友链信息（使用PageResult自动计算的start）
        int start = (pageResult.getStart() - 1); // PageResult的start是从1开始的，需要转换为从0开始
        List<FriendLink> friendLinkList = friendLinkService.queryPage(friendLink, start, pageResult.getPageSize());

        // 参数转换
        List<FriendLinkBO> friendLinkBOList = FriendLinkBOConverter.INSTANCE.convertEntityListToBO(friendLinkList);

        // 设置分页结果
        pageResult.setResult(friendLinkBOList);

        setCache(cacheKey, pageResult);
        // 返回结果
        return pageResult;
    }

    @Override
    public List<String> queryAllFriendLinkCategory() {
        if (log.isInfoEnabled()) {
            log.info("ClientFriendLinkDomainServiceImpl.queryAllFriendLinkCategory");
        }

        String cacheKey = redisUtil.buildKey("client", "friendLink", "category");
        List<String> cacheResult = getCache(cacheKey, new TypeReference<List<String>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 调用 service 获取友链的所有分类名称
        List<String> categoryNameList = friendLinkService.queryFriendLinkCategory();
        setCache(cacheKey, categoryNameList);
        return categoryNameList;
    }

    private <T> T getCache(String key, TypeReference<T> typeReference) {
        try {
            String cacheValue = redisUtil.get(key);
            if (cacheValue == null) {
                return null;
            }
            return OBJECT_MAPPER.readValue(cacheValue,
                    OBJECT_MAPPER.getTypeFactory().constructType(typeReference.getType()));
        } catch (Exception e) {
            log.warn("ClientFriendLinkDomainServiceImpl.getCache.error:key={}, msg={}", key, e.getMessage());
            return null;
        }
    }

    private void setCache(String key, Object value) {
        try {
            long ttl = FRIEND_LINK_CACHE_TIMEOUT_MINUTES +
                    ThreadLocalRandom.current().nextLong(FRIEND_LINK_CACHE_JITTER_MINUTES + 1);
            redisUtil.set(key, OBJECT_MAPPER.writeValueAsString(value), ttl, FRIEND_LINK_CACHE_TIMEUNIT);
        } catch (Exception e) {
            log.warn("ClientFriendLinkDomainServiceImpl.setCache.error:key={}, msg={}", key, e.getMessage());
        }
    }

    private String serializeKey(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("ClientFriendLinkDomainServiceImpl.serializeKey.error:{}", e.getMessage());
            return String.valueOf(obj);
        }
    }
}
